import * as CryptoJS from 'crypto-js'
import { uploadChunkApi } from '../api/bigfileupload'

interface UploadChunkParams {
  file: File;
  uploadId: string;
  chunkId: number;
  total: number;
}

interface ApiResponse<T = any> {
  code: number;
  msg?: string;
  data?: T;
}

interface ChunkResponseData {
  md5Str: string;
}
class UseUpdate {
  private md5Str: string[] = []
  constructor(private config = {
    shardSize: 1024 * 1024 * 2, // 以2MB为一个分片
    size: 0, // 文件总大小
    shardCount: 0 // 分片多少个
  }) {
    //   this.config = config
    this.md5Str = []
    // const config = ref({

    // })
  }

  // 读取上传文件
  // 返回存储的MD5值
  readMd5(index: number) {
    return this.md5Str[index]
  }

  // 判断当前文件是否属于这个任务
  async isSameTask(file: File, list: any): Promise<boolean> {
    try {
      // 获取当前文件特征
      const { md5 } = await this.getChunkFile(file, 0)

      // 打印调试信息
      console.log('MD5缓存:', this.md5Str)
      console.log('对比列表:', list)
      console.log('当前分片数据:', md5)
      console.log('当前分片索引:', md5 === list[0]?.etag)
      // 进行特征比对
      return md5 === list[0]?.etag
    } catch (error) {
      console.error('比对任务失败:', error)
      return false
    }
  }

  // 计算可以分多少个分片
  getShardCount(file: File): number {
    return Math.ceil(file.size / this.config.shardSize) // 总片数
  }

  // 进行分片处理
  async getChunkFile(fileData: File, index: number): Promise<{ file: Blob; md5: string }> {
    return new Promise((resolve, reject) => {
      const _start = index * this.config.shardSize
      this.config.size = fileData.size
      const _end = Math.min(this.config.size, _start + this.config.shardSize)
      const file = fileData.slice(_start, _end)
      const reader = new FileReader()

      // 成功回调
      reader.onload = (event) => {
        try {
          const wordArray = CryptoJS.lib.WordArray.create((event.target as any)!.result)
          const md5 = CryptoJS.MD5(wordArray).toString().toUpperCase()
          this.md5Str[index] = md5
          resolve({ file, md5 })
        } catch (err) {
          reject(err)
        }
      }

      // 错误回调
      reader.onerror = (error) => {
        reject(error)
      }

      reader.readAsArrayBuffer(file)
    })
  }

  /**
 * 创建分片上传表单数据
 */

  public createChunkFormData(
    chunk: File | Blob,
    uploadId: string,
    chunkId: number,
    total: number
  ): FormData {
    const form = new FormData()
    form.append('chunkFile', chunk)
    form.append('uploadId', uploadId)
    form.append('chunkId', chunkId.toString())
    form.append('total', total.toString())
    return form
  }

  /**
 * 验证分片完整性
 */
  validateChunkIntegrity(currentIndex: number, serverMd5: string): boolean {
    return this.readMd5(currentIndex) === serverMd5
  }

  /**
 * 执行分片上传（主方法）
 */
  async uploadChunk({
    file,
    uploadId,
    chunkId,
    total
  }: any): Promise<void> {
    try {
      const formData = this.createChunkFormData(
        file,
        uploadId,
        chunkId,
        total
      )

      const response = await uploadChunkApi(formData)

      await this.handleUploadResponse(
        response,
        chunkId,
        () => this.uploadChunk({ file, uploadId, chunkId, total })
      )
    } catch (error) {
      console.error('分片上传异常:', error)
      throw error
    }
  }

  handleUploadResponse = async (
    response: ApiResponse<ChunkResponseData>,
    currentIndex: number,
    retry: () => Promise<void>
  ): Promise<void> => {
    if (response.code === 1) {
      if (response.data?.md5Str && this.validateChunkIntegrity(currentIndex, response.data.md5Str)) {
        console.log(`分片${currentIndex}上传成功`);
      } else {
        console.warn(`分片${currentIndex}校验失败，重新上传`);
        await retry();
      }
    } else {
      throw new Error(response.msg || '分片上传失败');
    }
  }

  /**
 * 分片上传流程控制器
 */
  async uploadChunkController(
    params: any,
    uploaded: number | string,
    currentIndex: number
  ): Promise<void> {
    while (currentIndex < params.shardCount) {
      try {
        await this.uploadChunk({
          file: this.getChunkFile(params.file, currentIndex),
          uploadId: params.uploadId,
          chunkId: currentIndex + 1,
          total: params.shardCount
        })

        // this.updateProgress(uploaded, params.shardCount)
        currentIndex++
      } catch (error) {
        // handleUploadError(error, currentIndex)
        break
      }
    }
  }
}
export default new UseUpdate()
